﻿using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.ObjectBuilder;
using TestByWire.BuildStrategies;
using TestByWire.Factories;
using TestByWire.Factories.StubbingStrategies;

namespace TestByWire
{
	public class AutoInjectionBehavior : UnityContainerExtension
	{
		private readonly Type _testTargetType;
		private IStubInstanceFactory _stubInstanceFactory;

		public AutoInjectionBehavior(Type testTargetType)
		{
			if (testTargetType == null)
			{
				throw new ArgumentNullException("testTargetType");
			}

			_testTargetType = testTargetType;
		}

		protected override void Initialize()
		{
			var pipelineSettings = Container.Resolve<PipelineSettings>();
			pipelineSettings.DoNotStubList.Add(new DoNotStub(_testTargetType, null));
			pipelineSettings.DoNotStubList.Add(new DoNotStub(GetType(), null));

			Container.RegisterInstance(pipelineSettings, new ContainerControlledLifetimeManager());

			_stubInstanceFactory = new StubInstanceFactory(new StubCreationStrategyFactory(Container), Container);

			Container.RegisterInstance(_stubInstanceFactory);

			Context.Strategies.Add(new PreBuildRegistrationStrategy(Container), UnityBuildStage.PreCreation);
			Context.Strategies.Add(new AutoInjectionBuildStrategy(Container, _stubInstanceFactory, _testTargetType), UnityBuildStage.PreCreation);
			Context.Strategies.Add(new AutoReturnBuildStrategy(Container, _stubInstanceFactory, _testTargetType), UnityBuildStage.PreCreation);
			Context.Strategies.Add(new PostCreationBuildStrategy(Container), UnityBuildStage.PostInitialization);
		}
	}

	public class AutoInjectionBehavior<TTestTarget> : AutoInjectionBehavior
		where TTestTarget : class
	{
		public AutoInjectionBehavior()
			: base(typeof(TTestTarget))
		{
		}
	}
}
